home *** CD-ROM | disk | FTP | other *** search
- #include "FabTaskManager.h"
- #include "FabWmemman.h"
-
- enum {
- fabSysQueueType = 25,
- fabTimerQueueType
- };
-
- typedef struct SysTaskInfo SysTaskInfo, *SysTaskInfoPtr;
-
- struct SysTaskInfo {
- QElemPtr link;
- short qType;
- Boolean autoDestroy;
- void *parameter;
- void (*tmProc)(void *);
- #if !GENERATINGCFM
- long savedA5;
- #endif
- };
-
-
- struct TimerTaskInfo {
- TMTask theTask;
- void *parameter;
- void (*tmProc)(void *);
- #if !GENERATINGCFM
- long savedA5;
- #endif
- };
-
- typedef struct TimerTaskInfo TimerTaskInfo, *TimerTaskInfoPtr;
-
-
- struct NewTimerTaskInfo {
- QElemPtr qLink;
- int qType;
- Boolean autoDestroy;
- // long tmCount;
- UInt32 timeWakeUp;
- void *parameter;
- void (*tmProc)(void *);
- /*
- #if !GENERATINGCFM
- long savedA5;
- #endif
- */
- };
-
- typedef struct NewTimerTaskInfo NewTimerTaskInfo, *NewTimerTaskInfoPtr;
-
-
- static QHdr sSysQueueHdr = { 0, nil, nil};
- static QHdr sTimerQueueHdr = { 0, nil, nil};
-
-
- static OSErr gTimerTrigger_Held = -1;
-
-
- static void ExecuteSystemTask(SysTaskInfoPtr theTaskPtr);
- static void ExecuteTimerTask(NewTimerTaskInfoPtr theTaskPtr, UInt32 currentTime);
-
-
- #if GENERATINGCFM
- static TimerUPP gTriggerUPP;
-
- static void TimerTrigger(TMTaskPtr theTaskPtr);
- #else
- #pragma parameter TimerTrigger68K(__A1)
- static asm void TimerTrigger68K(TMTaskPtr tPtr);
- #endif
-
-
- void ExecuteSystemTask(SysTaskInfoPtr theTaskPtr)
- {
- void (*proc)(void *);
- void *param;
-
- (void) Dequeue((QElemPtr)theTaskPtr, &sSysQueueHdr);
- param = theTaskPtr->parameter;
- proc = theTaskPtr->tmProc;
- if (theTaskPtr->autoDestroy)
- Fab_DestroySystemTask(theTaskPtr);
- proc(param);
- }
-
- void ExecuteTimerTask(NewTimerTaskInfoPtr theTaskPtr, UInt32 currentTime)
- {
- void (*proc)(void *);
- void *param;
-
- if (theTaskPtr->qType < 0 &&
- currentTime > theTaskPtr->timeWakeUp) { // no need to be atomic here, runs at idle time
- theTaskPtr->qType &= (~0U >> 1); // portable form; turns off sign bit
- param = theTaskPtr->parameter;
- proc = theTaskPtr->tmProc;
- if (theTaskPtr->autoDestroy)
- Fab_DestroyTimerTask(theTaskPtr);
- proc(param);
- }
- }
-
-
- #define kTimerTask68KClassicSize 20
- #define kTimerTaskPPCSize 48
-
- void InitFabTaskManager_OldTimers(void)
- {
- long Gresp;
-
- #if GENERATINGCFM
- gTriggerUPP = NewTimerProc(TimerTrigger);
- #endif
-
- if (Gestalt(gestaltVMAttr, &Gresp) == noErr && (Gresp & (1L << gestaltVMPresent))) {
- gTimerTrigger_Held = HoldMemory(
- #if GENERATINGCFM
- TimerTrigger, kTimerTaskPPCSize
- #else
- TimerTrigger68K, kTimerTask68KClassicSize
- #endif
- );
- }
- }
-
- void CleanupFabTaskManager_OldTimers(void)
- {
- if (noErr == gTimerTrigger_Held)
- (void) UnholdMemory(
- #if GENERATINGCFM
- TimerTrigger, kTimerTaskPPCSize
- #else
- TimerTrigger68K, kTimerTask68KClassicSize
- #endif
- );
- }
-
-
- void Fab_ScheduleSystemTask(void *theTaskPtr)
- {
- #if !GENERATINGCFM
- long oldA5;
-
- oldA5 = SetA5(((SysTaskInfoPtr)theTaskPtr)->savedA5);
- #endif
-
- Enqueue((QElemPtr)theTaskPtr, &sSysQueueHdr);
-
- // CW 11 (68K) generates an A5-relative reference for the following
- // automatic initializer; had we placed this at the very beginning
- // of this function, before the SetA5 call,
- // we'd have crashed non-reproducibly (as Masatsugu Nagata, the first and only victim...)
- {
- ProcessSerialNumber myself = { 0, kCurrentProcess };
-
- (void) WakeUpProcess(&myself);
- }
-
- #if !GENERATINGCFM
- (void) SetA5(oldA5);
- #endif
- }
-
-
- void Fab_DestroySystemTask(void *theTaskPtr)
- {
- if (theTaskPtr)
- ffree(theTaskPtr);
- }
-
-
- void *Fab_CreateSystemTask(void (*theProc)(void *), void *param, Boolean autoDestroy)
- {
- SysTaskInfoPtr theTaskPtr;
-
- theTaskPtr = fmalloc(sizeof(SysTaskInfo));
- if (theTaskPtr) {
- theTaskPtr->qType = fabSysQueueType;
- theTaskPtr->autoDestroy = autoDestroy;
- theTaskPtr->parameter = param;
- theTaskPtr->tmProc = theProc;
-
- #if !GENERATINGCFM
- theTaskPtr->savedA5 = (long)LMGetCurrentA5();
- #endif
- }
- return theTaskPtr;
- }
-
- void CheckCallQueue(void)
- {
- SysTaskInfoPtr sHead;
- NewTimerTaskInfoPtr tHead, tNext;
- UInt32 ticks;
-
- while (sHead = (SysTaskInfoPtr)sSysQueueHdr.qHead)
- ExecuteSystemTask(sHead);
-
- ticks = TickCount();
- tHead = (NewTimerTaskInfoPtr)sTimerQueueHdr.qHead;
- if (tHead) {
- do {
- tNext = (NewTimerTaskInfoPtr)tHead->qLink;
- ExecuteTimerTask(tHead, ticks);
- tHead = tNext;
- }
- while (tNext);
- }
- }
-
-
- void *Fab_CreateTimerTask(void (*theProc)(void *), void *param, Boolean autoDestroy)
- {
- NewTimerTaskInfoPtr theTaskPtr;
-
- theTaskPtr = fmalloc(sizeof(NewTimerTaskInfo));
- if (theTaskPtr) {
- theTaskPtr->qType = fabTimerQueueType;
- theTaskPtr->autoDestroy = autoDestroy;
- theTaskPtr->parameter = param;
- theTaskPtr->tmProc = theProc;
-
- /*
- #if !GENERATINGCFM
- theTaskPtr->savedA5 = (long)LMGetCurrentA5();
- #endif
- */
- Enqueue((QElemPtr)theTaskPtr, &sTimerQueueHdr);
- }
- return theTaskPtr;
- }
-
- void Fab_DestroyTimerTask(void *theTaskPtr)
- {
- if (theTaskPtr) {
- (void) Dequeue((QElemPtr)theTaskPtr, &sTimerQueueHdr);
- ffree(theTaskPtr);
- }
- }
-
- // Note that we use LMGetTicks() instead of TickCount() because calling the latter
- // at interrupt time may lead to exciting debugging sessions.
- // I vaguely remember that the Ticks low mem global doesn't work under A/UX 2.
- // Let's hope it works under A/UX 3.
-
- #if !GENERATING68K
-
- // we use 16 instead of 17 for speed (vs. accuracy)
- #define msecs2ticks(m) ((m) / 16)
-
- void Fab_ScheduleTimerTask(void *theTaskPtr, UInt32 millisecs)
- {
- ProcessSerialNumber myself = { 0, kCurrentProcess };
- NewTimerTaskInfoPtr tptr = theTaskPtr;
- UInt32 ticksToGo;
-
- if (tptr && tptr->qType > 0) { // not already scheduled
- tptr->qType |= ~(~0U >> 1); // portable form; turns on sign bit
- ticksToGo = msecs2ticks(millisecs);
- tptr->timeWakeUp = LMGetTicks() + ticksToGo;
- if (ticksToGo == 0)
- (void) WakeUpProcess(&myself);
- }
- }
-
- void Fab_RescheduleTimerTask(void *theTaskPtr, UInt32 millisecs)
- {
- ProcessSerialNumber myself = { 0, kCurrentProcess };
- NewTimerTaskInfoPtr tptr = theTaskPtr;
- UInt32 ticksToGo;
-
- if (tptr) { // we don't care if it's already scheduled
- tptr->qType |= ~(~0U >> 1); // portable form; turns on sign bit
- ticksToGo = msecs2ticks(millisecs);
- tptr->timeWakeUp = LMGetTicks() + ticksToGo;
- if (ticksToGo == 0)
- (void) WakeUpProcess(&myself);
- }
- }
-
- void Fab_CancelTimerTask(void *theTaskPtr)
- {
- if (theTaskPtr) {
- ((NewTimerTaskInfoPtr)theTaskPtr)->qType &= (~0U >> 1); // portable form; turns off sign bit
- }
- }
-
- #else
-
- asm void Fab_ScheduleTimerTask(void *tPtr:__A0, UInt32 millisecs:__D0)
- {
- move.l a0,d1 // test for null pointer
- beq.s outofhere
- bset #7,struct (NewTimerTaskInfo.qType)(A0) // atomic test and set -- cool isn't it?
- bne.s outofhere // it was already scheduled
- LSR.L #4,D0 // msecs2ticks
- MOVE.L D0,D1
- ADD.L 0x016A,D0 // LMGetTicks()
- MOVE.L D0,struct (NewTimerTaskInfo.timeWakeUp)(A0)
- TST.L D1
- BNE.S outofhere
- PEA kCurrentProcess
- CLR.L -(SP)
- // MOVEA.L SP,A0
- SUBQ.L #2,SP
- PEA 2(SP) // current process
- // _WakeUpProcess
- MOVE.W #0x3C,-(SP)
- _OSDispatch
- LEA 10(SP),SP
- outofhere:
- rts
- }
-
- asm void Fab_RescheduleTimerTask(void *tPtr:__A0, UInt32 millisecs:__D0)
- {
- move.l a0,d1 // test for null pointer
- beq.s outofhere
- bset #7,struct (NewTimerTaskInfo.qType)(A0) // atomic test and set -- cool isn't it?
- LSR.L #4,D0 // msecs2ticks
- MOVE.L D0,D1
- ADD.L 0x016A,D0 // LMGetTicks()
- MOVE.L D0,struct (NewTimerTaskInfo.timeWakeUp)(A0)
- TST.L D1
- BNE.S outofhere
- PEA kCurrentProcess
- CLR.L -(SP)
- // MOVEA.L SP,A0
- SUBQ.L #2,SP
- PEA 2(SP) // current process
- // _WakeUpProcess
- MOVE.W #0x3C,-(SP)
- _OSDispatch
- LEA 10(SP),SP
- outofhere:
- rts
- }
-
- asm void Fab_CancelTimerTask(void *tPtr:__A0)
- {
- move.l a0,d0 // test for null pointer
- beq.s outofhere
- bclr #7,struct (NewTimerTaskInfo.qType)(A0)
- outofhere:
- rts
- }
-
- #endif
-
-
-
- static unsigned int gFabTimerTasks = 0;
-
- void *FabOld_CreateTimerTask(void (*theProc)(void *), void *param)
- {
- TimerTaskInfoPtr theTaskPtr;
-
- theTaskPtr = gFabTimerTasks > 50 ? nil: ffcalloc(sizeof(TimerTaskInfo));
- if (theTaskPtr) {
- ++gFabTimerTasks;
- ((TMTaskPtr)theTaskPtr)->tmAddr =
- #if GENERATINGCFM
- gTriggerUPP
- #else
- (TimerUPP)TimerTrigger68K
- #endif
- ;
- theTaskPtr->parameter = param;
- theTaskPtr->tmProc = theProc;
-
- #if !GENERATINGCFM
- theTaskPtr->savedA5 = (long)LMGetCurrentA5();
- #endif
- InsXTime((QElemPtr)theTaskPtr);
- }
-
- return theTaskPtr;
- }
-
- #if GENERATINGCFM
-
- void TimerTrigger(TMTaskPtr tPtr)
- {
- TimerTaskInfoPtr theTaskPtr = (TimerTaskInfoPtr)tPtr;
- void (*proc)(void *);
- void *param;
-
- param = theTaskPtr->parameter;
- proc = theTaskPtr->tmProc;
- proc(param);
- }
-
- #else
-
- asm void TimerTrigger68K(TMTaskPtr tPtr:__A1)
- {
- // we save A5 to A3
- // this is fine because we can trash A0-A3 and D0-D3
- // we JSR (A0) to a client that is written in C or Pascal
- // and thus our A3 will be preserved
- movea.l a5,a3 // save current A5
-
- movea.l struct (TimerTaskInfo.savedA5)(A1),a5 // set "right" A5
- move.l struct (TimerTaskInfo.parameter)(A1),-(sp) // push parameter
- movea.l struct (TimerTaskInfo.tmProc)(A1),a0
- jsr (a0)
- addq.l #4,sp // remove parameter, C calling conventions
-
- movea.l a3,a5 // restore A5
- rts
- }
-
- #endif
-
- void FabOld_DestroyTimerTask(void *theTaskPtr)
- {
- if (theTaskPtr) {
- --gFabTimerTasks;
- RmvTime((QElemPtr)theTaskPtr);
- ffree(theTaskPtr);
- }
- }
-
- void FabOld_ScheduleTimerTask(void *theTaskPtr, long millisecs)
- {
- if (theTaskPtr && ((TMTaskPtr)theTaskPtr)->qType > 0) // not already scheduled
- PrimeTime((QElemPtr)theTaskPtr, millisecs);
- }
-
- void FabOld_CancelTimerTask(void *theTaskPtr)
- {
- if (theTaskPtr) {
- RmvTime((QElemPtr)theTaskPtr);
- InsXTime((QElemPtr)theTaskPtr);
- }
- }
-
-